package com.heartunderblade.rpc;

import com.heartunderblade.rpc.Registry.Registry;
import com.heartunderblade.rpc.config.RegistryConfig;
import com.heartunderblade.rpc.config.RpcConfig;
import com.heartunderblade.rpc.constant.RpcConstant;
import com.heartunderblade.rpc.factory.RegistryFactory;
import com.heartunderblade.rpc.utils.ConfigUtilsPlus;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RpcApplication {
    //配置信息，volatile保证了rpcconfig被修改时，其他线程可见
    private static volatile RpcConfig rpcConfig;

    /**
     * 框架初始化，允许自定义配置
     */
    public static void  init(RpcConfig newRpcConfig){
        rpcConfig = newRpcConfig;
        log.info("rpc init, config = {}", newRpcConfig.toString());
        // 得到注册中心配置
        RegistryConfig registryConfig = rpcConfig.getRegistryConfig();
        //获取实例
        Registry registry = RegistryFactory.getInstance(registryConfig.getRegistry());
        //初始化注册中心
        registry.init(registryConfig);
        log.info("registry init, config = {}", newRpcConfig.toString());
        //创建并注册Shutdown Hook，JVM退出时执行操作
        Runtime.getRuntime().addShutdownHook(new Thread(registry::destroy));
    }
    /**
     * 无参初始化
     */
    public static void  init(){
        RpcConfig newRpcConfig;
        //从本地加载配置，
        try {
            newRpcConfig = ConfigUtilsPlus.loadConfig(RpcConfig.class, RpcConstant.DEFAULT_CONFIG_PREFIX);
        } catch (Exception e) {
            e.printStackTrace();
            //加载失败用默认值
            newRpcConfig = new RpcConfig();
        }
        //赋值类中rpcConfig
        init(newRpcConfig);
    }
    /**
     * 获取配置
     */
    public static RpcConfig getRpcConfig(){
        //双重检查锁单例模式，根据volatile 修饰的rpcconfig，
        // 如果未被初始化，即rpcConfig为null，那么就执行无参初始化，为保证rpcConfig是单例的，先做判断，为空
        //使用 synchronized 确保只有一个线程能在同一时刻进入同步块。
        // 在进入同步块后，做了第二次 rpcConfig == null 的检查。
        // 这是因为即使在第一个检查中发现 rpcConfig 为 null，其他线程可能已经在此时初始化了 rpcConfig。
        // 因此，第二次检查是必要的，避免多次初始化。
        if(rpcConfig == null){
            synchronized (RpcApplication.class){
                if(rpcConfig == null){
//            初始化返回
                    init();
                }
            }
        }
        return rpcConfig;
    }
}
